package k8ssvc

import (
	"context"
	"deployment-service/k8s"
	"fmt"
	"strings"

	underscore "github.com/ahl5esoft/golang-underscore"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	v1 "k8s.io/client-go/kubernetes/typed/core/v1"
	appsV1 "k8s.io/client-go/kubernetes/typed/apps/v1"
	typeV1 "k8s.io/api/apps/v1"
	"k8s.io/client-go/rest"
)

type namespaceAdapter struct {
	clientSet *kubernetes.Clientset
	config    *rest.Config
	ctx       context.Context
	podClient v1.PodInterface
	deploymentClient appsV1.DeploymentInterface
}

func (m namespaceAdapter) FindLatestPods(name string) (k8s.IK8sPod, error)  {
	pods, err := m.FindPods(name)
	if err != nil {
		return nil, err
	}

	if len(pods) == 0 {
		return nil, fmt.Errorf("找不到pod: %s", name)
	}

	// 查找最新的pod
	var lastPod k8s.IK8sPod
	for _, pod := range pods {
		startTime := pod.GetData().Status.StartTime

		if lastPod == nil {
			lastPod = pod
		} else if lastPod.GetData().Status.StartTime.Before(startTime) {
			lastPod = pod
		}
	}

	return lastPod, nil
}

func (m namespaceAdapter) FindPods(name string) ([]k8s.IK8sPod, error) {
	list, err := m.podClient.List(m.ctx, metav1.ListOptions{})
	if err != nil {
		return nil, err
	}

	var pods []k8s.IK8sPod
	underscore.Chain(list.Items).Where(func(r corev1.Pod, _ int) bool {
		return strings.Contains(r.Name, name)
	}).Map(func(r corev1.Pod, _ int) k8s.IK8sPod {
		return &podAdapter{
			clientSet: m.clientSet,
			config:    m.config,
			ctx:       m.ctx,
			pod:       r,
		}
	}).Value(&pods)
	if len(pods) > 0 {
		fmt.Println(pods[0].GetData().Kind)
		return pods, nil
	}

	return nil, fmt.Errorf("无效pod: %s", name)
}

func (m namespaceAdapter) FindDeployments(name string) ([]k8s.IK8sDeployment, error)  {
	list, err := m.deploymentClient.List(m.ctx, metav1.ListOptions{})
	if err != nil {
		return nil, err
	}

	var deployments []k8s.IK8sDeployment
	underscore.Chain(list.Items).Where(func(r typeV1.Deployment, _ int) bool {
		return strings.Contains(r.Name, name)
	}).Map(func(r typeV1.Deployment, _ int) k8s.IK8sDeployment {
		return &deploymentAdapter{
			clientSet: m.clientSet,
			config:    m.config,
			ctx:       m.ctx,
			deployment: r,
		}
	}).Value(&deployments)

	if len(deployments) > 0 {
		return deployments, nil
	}

	return nil, fmt.Errorf("无效deployment: %s", name)
}

func (m namespaceAdapter) FindReplicaSet(deploymentName string) ([]k8s.IK8sReplicaSet, error) {
	deployment, err := m.deploymentClient.Get(m.ctx, deploymentName, metav1.GetOptions{})
	if err != nil {
		return nil, err
	}

	selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector)
	if err != nil {
		return nil, err
	}

	listOpts := metav1.ListOptions{
		LabelSelector: selector.String(),
	}
	rs, err := m.clientSet.AppsV1().ReplicaSets(deployment.Namespace).List(m.ctx, listOpts)
	if err != nil {
		return nil, err
	}

	var replicaSet []k8s.IK8sReplicaSet
	underscore.Chain(rs.Items).Map(func(r typeV1.ReplicaSet, _ int) k8s.IK8sReplicaSet {
		return &replicaSetAdapter{
			clientSet: m.clientSet,
			config:    m.config,
			ctx:       m.ctx,
			replicaSet: r,
		}
	}).Value(&replicaSet)

	return replicaSet, nil
}

func (m namespaceAdapter) Rollback(deploymentName string, rollbackReplicaSetName string) error {
	deployment, err := m.deploymentClient.Get(m.ctx, deploymentName, metav1.GetOptions{})
	if err != nil {
		return err
	}

	selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector)
	if err != nil {
		return err
	}

	listOpts := metav1.ListOptions{
		LabelSelector: selector.String(),
	}
	rs, err := m.clientSet.AppsV1().ReplicaSets(deployment.Namespace).List(m.ctx, listOpts)
	if err != nil {
		return err
	}

	for _, v := range rs.Items {
		if v.ObjectMeta.Name == rollbackReplicaSetName {
			deployment.Spec.Template = v.Spec.Template
			_, err = m.clientSet.AppsV1().Deployments(deployment.Namespace).Update(m.ctx, deployment, metav1.UpdateOptions{})
			if err != nil {
				return err
			}
			return nil
		}
	}

	return fmt.Errorf("找不到回滾的版本:%s", rollbackReplicaSetName)
}